#!/bin/bash

POLICY_CRDS_PATH="/tmp/policy_crds.json"
APISERVER=https://kubernetes.default.svc
SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
TOKEN=$(cat ${SERVICEACCOUNT}/token)
NAMESPACE=$(cat ${SERVICEACCOUNT}/namespace)
CACERT=${SERVICEACCOUNT}/ca.crt
ra_token=
tenant_id=
agent_id=
profile_id=
cluster_id=
latest_policy_version=1

if [ -f $POLICY_CRDS_PATH ]; then
    chmod 644 $POLICY_CRDS_PATH
fi

load_agent_details()
{
    tenant_id=$(awk -F\" '/Tenant ID/{print $4}' /etc/cp/conf/agent_details.json)
    agent_id=$(awk -F\" '/Agent ID/{print $4}' /etc/cp/conf/agent_details.json)
    profile_id=$(awk -F\" '/Profile ID/{print $4}' /etc/cp/conf/agent_details.json)
    cluster_id=$(echo $(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/ ) \
        | /etc/cp/bin/yq eval '.items' - \
        | /etc/cp/bin/yq eval '.[] | select(.metadata.name | contains("kube-system"))' - \
        | /etc/cp/bin/yq eval '.metadata.uid' -)
}

get_latest_policy_version()
{
    bucket_list=$(curl -s -w "%{http_code}\n" --request GET \
        -H "user-agent: Infinity Next (a7030abf93a4c13)" -H "Authorization: Bearer ${ra_token}" \
        "$var_fog/agents-core/storage/?list-type=2&prefix=${tenant_id}/${profile_id}")
    paths_list=$(echo $bucket_list  | awk -F'<Key>|</Key>' '/policy-/ {for (i = 1; i <= NF; i++) if ($i ~ /policy/) print $i}')

    prefix="${tenant_id}/${profile_id}"
    paths=$(echo $paths_list | tr " " "\n" | grep / )
    for path in $paths; do
        new_path=$(echo ${path%/*})
        version=$(echo ${new_path##*/})
        if [[ $version =~ ^-?[0-9]+$ ]] && [  $latest_policy_version -lt $version  ]; then
            latest_policy_version=$version
        fi
    done
    latest_policy_version=$((latest_policy_version+1))
    echo "Policy version: $latest_policy_version"
}

concat_to_policy()
{
    api_version="$1"
    crd_to_concat="$2"
    is_first=$3
    if [ ! -z $is_first ]; then
        POLICY="$POLICY \"$crd_to_concat\": "
    else
        POLICY="$POLICY, \"$crd_to_concat\": "
    fi
    CRD=$(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" \
        -X GET ${APISERVER}/apis/openappsec.io/$api_version/$crd_to_concat)
    CRD=$(echo $CRD|tr -d '\n')
    if [ -z "$CRD" ]; then
        CRD="{}"
    fi
    POLICY="$POLICY $CRD"
}

get_api_version()
{
    CRD=$(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" \
        -X GET ${APISERVER}/apis/openappsec.io/v1beta2/policies)
    CRD=$(echo $CRD|tr -d '\n')
    # if CRD is not empty and does not contain "page not found" then it is v1beta2
    if [ ! -z "$CRD" ] && ! echo "$CRD" | grep -q "page not found"; then
        echo "v1beta2"
    else
        echo "v1beta1"
    fi
}

generate_policy()
{
    POLICY="{ \"Policy\": {"

    api_version=$(get_api_version)

    concat_to_policy $api_version "policies" true
    if [ "$api_version" = "v1beta2" ]; then
        concat_to_policy $api_version "threatpreventionpractices"
        concat_to_policy $api_version "accesscontrolpractices"
    else
        concat_to_policy $api_version "practices"
    fi
    concat_to_policy $api_version "logtriggers"
    concat_to_policy $api_version "customresponses"
    concat_to_policy $api_version "exceptions"
    concat_to_policy $api_version "sourcesidentifiers"
    concat_to_policy $api_version "trustedsources"

    POLICY="$POLICY, \"assets\": { \"items\":[ "

    FIRST="1"
    all_ingresses=$(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" \
        -X GET ${APISERVER}/apis/networking.k8s.io/v1/ingresses)
    namespaces=$(echo $all_ingresses | /etc/cp/bin/yq eval '.items[].metadata.namespace' -)

    for ns in ${namespaces}; do
        ingress_in_ns=$(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" \
            -X GET ${APISERVER}/apis/networking.k8s.io/v1/namespaces/${ns}/ingresses)
        ingress_list=$(echo $ingress_in_ns | /etc/cp/bin/yq eval '.items[].metadata.name' -)
        for ingress_name in ${ingress_list}; do
            ingress_crd=$(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" \
                -X GET ${APISERVER}/apis/networking.k8s.io/v1/namespaces/${ns}/ingresses/${ingress_name})

            if echo $ingress_crd | grep -n "openappsec" 1>/dev/null; then
                ingress_crd=$(echo $ingress_crd | tr -d '\n')
            fi
            if [ "$FIRST" = "0" ]; then
                POLICY="$POLICY ,"
            fi
            POLICY="$POLICY $ingress_crd"
            FIRST="0"
        done
    done

    all_policyactivations=$(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" \
        -X GET ${APISERVER}/apis/openappsec.io/v1beta2/policyactivations)
    policyactivation_list=$(echo $all_policyactivations | /etc/cp/bin/yq eval '.items[].metadata.name' -)
    for policyactivation_name in ${policyactivation_list}; do
        policyactivation_crd=$(curl -s --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" \
            -X GET ${APISERVER}/apis/openappsec.io/v1beta2/policyactivations/${policyactivation_name})
        policyactivation_crd=$(echo $policyactivation_crd | tr -d '\n')
        if [ "$FIRST" = "0" ]; then
            POLICY="$POLICY ,"
        fi
        POLICY="$POLICY $policyactivation_crd"
        FIRST="0"
    done

    POLICY="$POLICY ] } } }"
    echo $POLICY > $POLICY_CRDS_PATH
}

upload_the_crds_to_s3()
{
    echo "Uploading local configuration to cloud..."
    upload_res="$(curl -o /dev/null -s -w "%{http_code}\n" --progress-bar --request PUT -T "${POLICY_CRDS_PATH}" \
        -H "user-agent: Infinity Next (a7030abf93a4c13)" -H "Content-Type: application/json" \
        -H "Authorization: Bearer ${ra_token}" \
        "$var_fog/agents-core/storage/$tenant_id/$profile_id/$latest_policy_version/policy-$cluster_id.json")"

    if test "$upload_res" != "200"; then
        echo "Failed uploading CRDs to cloud: Failed Error code ${upload_res}"
        return 1
    fi

    check_file_exists="$(curl -o /dev/null -s -w "%{http_code}\n" --request GET -H "user-agent: Infinity Next (a7030abf93a4c13)" \
        -H "Authorization: Bearer ${ra_token}" \
        "$var_fog/agents-core/storage/$tenant_id/$profile_id/$latest_policy_version/policy-$cluster_id.json")"
    if test "$check_file_exists" != "200"; then
        echo "Failed uploading CRD to cloud: Failed on checking the file.  Error code ${check_file_exists}"
        return 1
    fi
}

send_notification_to_the_fog()
{
    correlation_id=$(cat /proc/sys/kernel/random/uuid)
    DATE=$(date "+%FT%T.000")
    upload_res=$(curl -o /dev/null -s -w "%{http_code}\n" --request POST "$var_fog/api/v1/agents/events/bulk" \
        -H "X-Trace-Id:${correlation_id}" --header "Authorization: Bearer ${ra_token}" \
        --header "user-agent: Infinity Next (a7030abf93a4c13)" \
        --header "Content-Type: application/json" \
        --header "x-rate-limit-product-type: openappsec" \
        --data "{\"logs\": [{\"log\": {\"eventTime\": \"$DATE\",\"eventName\": \
        \"Agent started onboarding process to cloud management\",\"eventSeverity\": \"Info\",\"eventPriority\": \
        \"Urgent\",\"eventLogLevel\": \"info\",\"eventType\": \"Event Driven\",\"eventLevel\": \"Log\",\"eventAudience\": \
        \"Internal\",\"eventAudienceTeam\": \"Agent Core\",\"eventFrequency\": 0,\"eventSource\": {\"serviceName\": \
        \"Orchestration\",\"agentId\": \"$agent_id\",\"tenantId\": \"$tenant_id\",\"serviceId\": \"1\",\"issuingEngineVersion\": \
        \"1.2229.123456\",\"issuingEngine\": \"onboardingInfoProvider\"},\"eventData\": {\"eventObject\": {\"onboardingInfo\": \
        {\"policyVersion\": $latest_policy_version,\"clusterId\": \"$cluster_id\",\"profileId\": \"$profile_id\"}}},\
        \"eventTags\": [\"Orchestration\"]}, \"tenantId\": \"$tenant_id\", \"id\": 1}]}")

    if test "$upload_res" != "200"; then
        sleep 5
        upload_res=$(curl -o /dev/null -s -w "%{http_code}\n" --request POST "$var_fog/api/v1/agents/events/bulk" \
            -H "X-Trace-Id:${correlation_id}" --header "Authorization: Bearer ${ra_token}" \
            --header "user-agent: Infinity Next (a7030abf93a4c13)" \
            --header "Content-Type: application/json" \
            --header "x-rate-limit-product-type: openappsec" \
            --data "{\"logs\": [{\"log\": {\"eventTime\": \"$DATE\",\"eventName\": \
            \"Agent started onboarding process to cloud management\",\"eventSeverity\": \"Info\",\"eventPriority\": \
            \"Urgent\",\"eventLogLevel\": \"info\",\"eventType\": \"Event Driven\",\"eventLevel\": \"Log\",\
            \"eventAudience\": \"Internal\",\"eventAudienceTeam\": \"Agent Core\",\"eventFrequency\": 0,\"eventSource\": \
            {\"serviceName\": \"Orchestration\",\"agentId\": \"$agent_id\",\"tenantId\": \"$tenant_id\",\
            \"serviceId\": \"1\",\"issuingEngineVersion\": \"1.2229.123456\",\"issuingEngine\": \"onboardingInfoProvider\"},\
            \"eventData\": {\"eventObject\": {\"onboardingInfo\": {\"policyVersion\": $latest_policy_version,\
            \"clusterId\": \"$cluster_id\",\"profileId\": \"$profile_id\"}}},\"eventTags\": [\"Orchestration\"]}, \
            \"tenantId\": \"$tenant_id\", \"id\": 1}]}")
        if test "$upload_res" != "200"; then
            echo "Failed to notify the FOG on the new CRDs: Failed Error code ${upload_res}"
            return 1
        fi
    fi
}

poll_for_status_file()
{
    correlation_id=$(cat /proc/sys/kernel/random/uuid)

    attempt_counter=0
    max_attempts=18

    until [ ${attempt_counter} -eq ${max_attempts} ]; do
        if [ ${attempt_counter} -eq ${max_attempts} ];then
            echo "Max attempts reached"
            exit 1
        fi
        file_exists="$(curl -s -w "%{http_code}\n" --request GET -H "user-agent: Infinity Next (a7030abf93a4c13)" \
            -H "Authorization: Bearer ${ra_token}" \
            "$var_fog/agents-core/storage/$tenant_id/$profile_id/$latest_policy_version/status-$cluster_id.json")"

        check_file_exists=$(echo $file_exists | grep 200)
        if [ ! -z "$check_file_exists" ]; then
            FAILURE=$(echo $file_exists | grep "false")
            if [ ! -z "$FAILURE" ]; then
                echo "Failed creating the Assets: $(echo $file_exists | cut -c27- | cut -d '"' -f 1)"
                exit 1
            else
                echo "."
                return 0
            fi
        else
            echo -n '.'
            attempt_counter=$(($attempt_counter+1))
            sleep 10
        fi
    done
    echo "Error: Status file was not generated"
    exit 1
}

upload_crds_to_the_cloud()
{
    STATUS="FAILURE"
    load_agent_details
    get_latest_policy_version
    generate_policy

    upload_the_crds_to_s3
    if [ "$?" = "1" ]; then
        echo "Failed uploading the CRDs to S3"
        exit 1
    fi

    send_notification_to_the_fog
    if [ "$?" = "1" ]; then
        echo "Failed Notifying to FOG"
        exit 1
    fi

    poll_for_status_file
    if [ "$?" = "0" ]; then
        STATUS="SUCCESS"
    fi

    if [ "$STATUS" = "FAILURE" ]; then
        echo "Failed to upload CRDs to the cloud"
        exit 1
    fi
}

usage()
{
    echo "Usage: $0 --token <token> [options...] ]"
    echo "    --token <token>                     : Registration token"
    echo "Options:"
    echo "    --fog       <fog address>          : Namespace with the relevant Helm Chart"
    echo "    --upload_policy_only               : Upload policy to the fog, withput changing agent mode"
    echo "    --debug                            : Keep the debuging files"
    exit 255
}

validate_flags()
{
    if [ -z $var_token ]; then
        usage
        exit 1
    fi
}

validate_arg_value_exists()
{
    if test "$2" = "1"; then
        echo "Error: The script is missing value for '$1'"
        usage
        exit 1
    fi
}

debug_mode="false"

while true; do
    if [ "$1" = "--token" ]; then
        validate_arg_value_exists "$1" "$#"
        shift
        var_token="$1"
    elif [ "$1" = "--fog" ]; then
        validate_arg_value_exists "$1" "$#"
        shift
        var_fog="$1"
    elif [ "$1" = "--access_token" ] || [ "$1" = "-at" ]; then
        validate_arg_value_exists "$1" "$#"
        shift
        ra_token="$1"
    elif [ "$1" = "--debug" ]; then
        debug_mode="true"
    elif [ -z "$1" ]; then
        break
    fi
    shift
done

if [ -z "$var_fog" ]; then
    var_fog=$(awk -F\" '/Fog domain/{print $4}' /etc/cp/conf/agent_details.json)
    var_fog="https://$var_fog"
fi

upload_crds_to_the_cloud
if [ "$?" = "0" ]; then
    echo "SUCCESS"
fi
if [ "$debug_mode" = "false" ]; then
    rm $POLICY_CRDS_PATH
fi

exit 0
